﻿#ifndef OPENGLWIDGET_H
#define OPENGLWIDGET_H

#include <QOpenGLWidget>
//#include <QOpenGLExtraFunctions>
#include <QOpenGLFunctions_3_3_Core>
#include <QOpenGLFunctions_1_1>
#include <QOpenGLShaderProgram>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QMatrix3x3>
#include <QMatrix4x4>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QVector>

class OpenGLWidget : public QOpenGLWidget, QOpenGLFunctions_1_1
{
    Q_OBJECT
public:
    explicit OpenGLWidget(QWidget *parent = nullptr);
    ~OpenGLWidget();
    void renderModel(QString path);
    void setWirefame(bool checked);
    void setProjection(bool checked);

protected:
    void initializeGL() override;
    void resizeGL(int width, int height) override;
    void paintGL() override;
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void wheelEvent(QWheelEvent *event) override;

private:
    // 着色器程序
    QOpenGLShaderProgram m_Shaderprogram;
    /*******************************************************************************
     * VAO(Vertex Array Object）顶点数组对象
     * VBO调用glVertexAttribPoint的结果被记录到 VAO 中，
     * 最终绘制的时候直接通过 VAO 中存储的指针去缓冲区取数据，
     * 而不需要再重复解析 VBO
     ******************************************************************************/
    QOpenGLVertexArrayObject m_VAO;
    /*******************************************************************************
     * VBO(Vertex Buffer Object) 顶点缓冲对象
     * VBO 是显存中的一片缓冲区域，存放从内存中提交过来的顶点数据。
     * GPU 绘制时，需要对 VBO 中的数据进行解析，以便将数据正确的提交给着色器中对应的属性。
     * 例如，GPU 需要知道 VBO 中哪一块数据是某个顶点的坐标，哪一块数据是某个顶点的顶点颜色等，
     * 通过调用 glVertexAttribPointer 方法来设置解析规则，GPU 能够取到正确的数据供着色器使用
     ******************************************************************************/
    QOpenGLBuffer m_VBO;
    /*******************************************************************************
     * EBO(Element Buffer Object)元素缓存对象，也叫索引缓存对象IBO（Index Buffer Object）
     * VBO 中存放的是去重后的顶点数据，当顶点复用数目较多时可以节省很多存储空间，
     * 另外单独开辟一个EBO缓冲区来存储每个顶点的实际数据在 VBO 中对应的下标值，
     * 在提交时将EBO信息也提交，计算结果得到 VAO，绘制时绑定 VAO 来访问顶点数据。
     ******************************************************************************/
    QOpenGLBuffer m_EBO;

    // 保存鼠标上一次的位置
    QVector2D m_MousePos;

    QMatrix4x4 m_Model;
    QMatrix4x4 m_View;
    QMatrix4x4 m_Projection;

    // 四元数
    QQuaternion m_Rotation;

    GLfloat m_XTrans = 0, m_YTrans = 0, m_ZTrans = 0;

    // 顶点数组
    QVector<GLfloat> m_Vertices = {/*
        -0.5,-0.5,-0.5,-0.5,-0.5,-0.5,
        -0.5,-0.5,0.5,-0.5,-0.5,0.5,
        0.5,-0.5,0.5,0.5,-0.5,0.5,
        0.5,-0.5,-0.5,0.5,-0.5,-0.5,
        -0.5,0.5,-0.5,-0.5,0.5,-0.5,
        -0.5,0.5,0.5,-0.5,0.5,0.5,
        0.5,0.5,0.5,0.5,0.5,0.5,
        0.5,0.5,-0.5,0.5,0.5,-0.5*/
    };
    // 顶点索引
    QVector<GLint> m_Indices = {/*
        0,2,1,
        0,2,3,
        2,5,1,
        2,5,6,
        2,7,3,
        2,7,6,
        0,5,1,
        0,5,4,
        4,6,5,
        4,6,7,
        0,7,4,
        0,7,3*/
    };
    QVector<float> m_Position;
    QVector<GLfloat> m_Normal;//读文件时的两个临时变量顶点位置、法向量

    bool m_IsCheckedProjection{true};
};

#endif // OPENGLWIDGET_H
